package com.rfsp.mcp.service;

import java.io.File;
import java.io.FileInputStream;
import java.security.PrivateKey;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.rfsp.common.util.FileUtil;
import com.rfsp.common.mapper.ParamMapper;
import com.rfsp.common.pojo.po.ParamPO;

import cfca.com.itextpdf.text.pdf.PdfArray;
import cfca.paperless.client.bean.SignLocation;
import cfca.paperless.client.servlet.PaperlessClient;
import cfca.paperless.client.util.PaperlessClientUtil;
import cfca.paperless.client.util.StrategyUtil;
import cfca.paperless.util.IoUtil;
import cfca.paperless.util.StringUtil;
import cfca.paperless.util.validity.ValidityUtil;
import cfca.sadk.algorithm.common.Mechanism;
import cfca.sadk.util.Base64;
import cfca.sadk.util.KeyUtil;
import cfca.seal.sadk.PdfSealVerifier;
import tk.mybatis.mapper.entity.Example;

@Service
public class CfcaService {
	
	private static final Logger logger = LoggerFactory.getLogger(CfcaService.class);
	
	
	@Autowired
	private ParamMapper paramMapper;
	
	
	public String sealAutoPdfWithPath(String pdfPath, String outPath, String sealImageBase64Str, String systemNo) throws Exception {
		
		String[] returnObj = null;
		
		Example example = new Example(ParamPO.class);
		example.createCriteria().andLike("paraCode", "CFCA_%");
		List<ParamPO> mDDParaList = paramMapper.selectByExample(example);
		
		Map<String, String> paraMap = new HashMap<String, String>();
		if(mDDParaList != null && mDDParaList.size() > 0) {
			for(ParamPO mDDPara:mDDParaList) {
				paraMap.put(mDDPara.getParaCode(), mDDPara.getParaValue());
			}
		}
		
		String CFCA_SERVICE_URL = paraMap.get("CFCA_SERVICE_URL");//cfca服务地址
		String CFCA_CONNECT_TIMEOUT = paraMap.get("CFCA_CONNECT_TIMEOUT");//连接超时时间
		String CFCA_READ_TIMEOUT = paraMap.get("CFCA_READ_TIMEOUT");//读取超时时间
		String CFCA_CER_PATH = paraMap.get("CFCA_CER_PATH");//cer文件路径
		String CFCA_PFX_PATH = paraMap.get("CFCA_PFX_PATH");//pfx文件路径
		String CFCA_PFX_PASSWORD = paraMap.get("CFCA_PFX_PASSWORD");//pfx文件密码
		String CFCA_SEAL_IMAGE_PATH = paraMap.get("CFCA_SEAL_IMAGE_PATH");//签章默认图片路径
		String CFCA_SEAL_IMAGE_SIZE = paraMap.get("CFCA_SEAL_IMAGE_SIZE");//签章图片尺寸
		String CFCA_SEAL_KEYWORD = "为确保信息安全";//paraMap.get("CFCA_SEAL_KEYWORD");//签章图片定位关键词
		String CFCA_SEAL_POSITION_X = paraMap.get("CFCA_SEAL_POSITION_X");//签章图片与关键词的X轴相对位置
		String CFCA_SEAL_POSITION_Y = paraMap.get("CFCA_SEAL_POSITION_Y");//签章图片与关键词的Y轴相对位置
		String CFCA_OPERATOR_CODE = paraMap.get("CFCA_OPERATOR_CODE");//操作员编号
		String CFCA_CHANNEL_CODE = paraMap.get("CFCA_CHANNEL_CODE");//渠道编号
		
		logger.info("CFCA_SERVICE_URL="+CFCA_SERVICE_URL);
		logger.info("CFCA_CONNECT_TIMEOUT="+CFCA_CONNECT_TIMEOUT);
		logger.info("CFCA_READ_TIMEOUT="+CFCA_READ_TIMEOUT);
		logger.info("CFCA_CER_PATH="+CFCA_CER_PATH);
		logger.info("CFCA_PFX_PATH="+CFCA_PFX_PATH);
		logger.info("CFCA_PFX_PASSWORD="+CFCA_PFX_PASSWORD);
		logger.info("CFCA_SEAL_IMAGE_PATH="+CFCA_SEAL_IMAGE_PATH);
		logger.info("CFCA_SEAL_IMAGE_SIZE="+CFCA_SEAL_IMAGE_SIZE);
		logger.info("CFCA_SEAL_KEYWORD="+CFCA_SEAL_KEYWORD);
		logger.info("CFCA_SEAL_POSITION_X="+CFCA_SEAL_POSITION_X);
		logger.info("CFCA_SEAL_POSITION_Y="+CFCA_SEAL_POSITION_Y);
		logger.info("CFCA_OPERATOR_CODE="+CFCA_OPERATOR_CODE);
		logger.info("CFCA_CHANNEL_CODE="+CFCA_CHANNEL_CODE);
		
		logger.info("pdfPath="+pdfPath);
		logger.info("sealImageBase64Str="+sealImageBase64Str);
		
		
		// 初始化客户端对象
		PaperlessClient clientBean = new PaperlessClient(CFCA_SERVICE_URL, Integer.valueOf(CFCA_CONNECT_TIMEOUT), Integer.valueOf(CFCA_READ_TIMEOUT));// 无纸化辅助接口的访问URL
		String pdfSuffix = IoUtil.getFileNameSuffix(pdfPath);
		if (!"pdf".equals(pdfSuffix)) {
			throw new Exception("所选文件不是pdf文件");
		}
		
		String inputPath = Base64.toBase64String(FileUtil.getRootPath(pdfPath).getBytes());
		String outPutPath = Base64.toBase64String(FileUtil.getRootPath(outPath).getBytes());
		
		String pngSuffix = IoUtil.getFileNameSuffix(FileUtil.getRootPath(CFCA_SEAL_IMAGE_PATH));
		if (!"png".equals(pngSuffix)) {
			throw new Exception("所选文件不是png文件,签章图片文件只支持png格式图片");
		}
		
		
		// 签章位置
		SignLocation signLocation = null;
		// 策略XML
		String strategyXml = "";
		
		
		// 图章图片
		byte[] sealImage = null;
		if(StringUtils.isNotBlank(sealImageBase64Str)) {//能够去的图章
			sealImage = Base64.decode(sealImageBase64Str);
			signLocation = new SignLocation(CFCA_SEAL_KEYWORD, "R", Integer.valueOf(CFCA_SEAL_POSITION_X), Integer.valueOf(CFCA_SEAL_POSITION_Y));
			strategyXml = StrategyUtil.createClientSealStrategyXml("sealStrategy", "china", sealImage, Integer.valueOf(CFCA_SEAL_IMAGE_SIZE), signLocation, Mechanism.SHA1, null);
		}else {//使用系统默认图章
			sealImage = FileUtils.readFileToByteArray(new File(FileUtil.getRootPath(CFCA_SEAL_IMAGE_PATH)));
			signLocation = new SignLocation("通知书回执", "R", Integer.valueOf(70), Integer.valueOf(-10));
			strategyXml = StrategyUtil.createClientSealStrategyXml("sealStrategy", "china", sealImage, Integer.valueOf(60), signLocation, Mechanism.SHA1, null);
		}
		
		
		byte[] pdf = FileUtils.readFileToByteArray(new File(FileUtil.getRootPath(pdfPath)));
		byte[] sealedPdfData = clientBean.sealAutoPdf(pdf, strategyXml, CFCA_OPERATOR_CODE, CFCA_CHANNEL_CODE);
		// 返回错误信息
		String errorRsString = PaperlessClientUtil.isError(sealedPdfData);
		if (StringUtils.isBlank(errorRsString)) {
			IoUtil.write(FileUtil.getRootPath(pdfPath), sealedPdfData);
			checkPdfData(sealedPdfData, true);
		} else {
			// 处理结果为异常，打印出错误码和错误信息
			throw new Exception("签章合成失败:"+errorRsString);
		}
		
		
//		String outputFilePath = clientBean.sealAutoPdfWithPath(systemNo, pdfPath, outPath, strategyXml, CFCA_OPERATOR_CODE, CFCA_CHANNEL_CODE, "0", "false");
		
		
		return pdfPath;
	}
	
	
	
	public String[] autoCalculatePdfHash(String pdfPath, String sealImageBase64Str, String bizCode) throws Exception {
		
		String[] returnObj = null;
		
		Example example = new Example(ParamPO.class);
		example.createCriteria().andLike("paraCode", "CFCA_%");
		List<ParamPO> mDDParaList = paramMapper.selectByExample(example);
		
		Map<String, String> paraMap = new HashMap<String, String>();
		if(mDDParaList != null && mDDParaList.size() > 0) {
			for(ParamPO mDDPara:mDDParaList) {
				paraMap.put(mDDPara.getParaCode(), mDDPara.getParaValue());
			}
		}
		
		String CFCA_SERVICE_URL = paraMap.get("CFCA_SERVICE_URL");//cfca服务地址
		String CFCA_CONNECT_TIMEOUT = paraMap.get("CFCA_CONNECT_TIMEOUT");//连接超时时间
		String CFCA_READ_TIMEOUT = paraMap.get("CFCA_READ_TIMEOUT");//读取超时时间
		String CFCA_CER_PATH = paraMap.get("CFCA_CER_PATH");//cer文件路径
		String CFCA_PFX_PATH = paraMap.get("CFCA_PFX_PATH");//pfx文件路径
		String CFCA_PFX_PASSWORD = paraMap.get("CFCA_PFX_PASSWORD");//pfx文件密码
		String CFCA_SEAL_IMAGE_PATH = paraMap.get("CFCA_SEAL_IMAGE_PATH");//签章默认图片路径
		String CFCA_SEAL_IMAGE_SIZE = paraMap.get("CFCA_SEAL_IMAGE_SIZE");//签章图片尺寸
		String CFCA_SEAL_KEYWORD = paraMap.get("CFCA_SEAL_KEYWORD");//签章图片定位关键词
		String CFCA_SEAL_POSITION_X = paraMap.get("CFCA_SEAL_POSITION_X");//签章图片与关键词的X轴相对位置
		String CFCA_SEAL_POSITION_Y = paraMap.get("CFCA_SEAL_POSITION_Y");//签章图片与关键词的Y轴相对位置
		String CFCA_OPERATOR_CODE = paraMap.get("CFCA_OPERATOR_CODE");//操作员编号
		String CFCA_CHANNEL_CODE = paraMap.get("CFCA_CHANNEL_CODE");//渠道编号
		
		logger.info("CFCA_SERVICE_URL="+CFCA_SERVICE_URL);
		logger.info("CFCA_CONNECT_TIMEOUT="+CFCA_CONNECT_TIMEOUT);
		logger.info("CFCA_READ_TIMEOUT="+CFCA_READ_TIMEOUT);
		logger.info("CFCA_CER_PATH="+CFCA_CER_PATH);
		logger.info("CFCA_PFX_PATH="+CFCA_PFX_PATH);
		logger.info("CFCA_PFX_PASSWORD="+CFCA_PFX_PASSWORD);
		logger.info("CFCA_SEAL_IMAGE_PATH="+CFCA_SEAL_IMAGE_PATH);
		logger.info("CFCA_SEAL_IMAGE_SIZE="+CFCA_SEAL_IMAGE_SIZE);
		logger.info("CFCA_SEAL_KEYWORD="+CFCA_SEAL_KEYWORD);
		logger.info("CFCA_SEAL_POSITION_X="+CFCA_SEAL_POSITION_X);
		logger.info("CFCA_SEAL_POSITION_Y="+CFCA_SEAL_POSITION_Y);
		logger.info("CFCA_OPERATOR_CODE="+CFCA_OPERATOR_CODE);
		logger.info("CFCA_CHANNEL_CODE="+CFCA_CHANNEL_CODE);
		
		logger.info("pdfPath="+pdfPath);
		logger.info("sealImageBase64Str="+sealImageBase64Str);
		
		
		
		// 初始化客户端对象
		PaperlessClient clientBean = new PaperlessClient(CFCA_SERVICE_URL, Integer.valueOf(CFCA_CONNECT_TIMEOUT), Integer.valueOf(CFCA_READ_TIMEOUT));// 无纸化辅助接口的访问URL
		String pdfSuffix = IoUtil.getFileNameSuffix(pdfPath);
		if (!"pdf".equals(pdfSuffix)) {
			throw new Exception("所选文件不是pdf文件");
		}
		byte[] pdf = FileUtils.readFileToByteArray(new File(FileUtil.getRootPath(pdfPath)));
		// 公钥证书
		byte[] x509Cert = FileUtils.readFileToByteArray(new File(FileUtil.getRootPath(CFCA_CER_PATH)));
//					X509Cert cert = new X509Cert(x509Cert);
		// 私钥
		PrivateKey privateKey = KeyUtil.getPrivateKeyFromPFX(new FileInputStream(FileUtil.getRootPath(CFCA_PFX_PATH)), CFCA_PFX_PASSWORD);

		String pngSuffix = IoUtil.getFileNameSuffix(FileUtil.getRootPath(CFCA_SEAL_IMAGE_PATH));
		if (!"png".equals(pngSuffix)) {
			throw new Exception("所选文件不是png文件,签章图片文件只支持png格式图片");
		}
		
		// 签章位置
		SignLocation signLocation = null;
		
		// 策略XML
		String strategyXml = "";
		
		// 图章图片
		byte[] sealImage = null;
		if(StringUtils.isNotBlank(sealImageBase64Str)) {//能够去的图章
			sealImage = Base64.decode(sealImageBase64Str);
			signLocation = new SignLocation("签署日期", "R", 40, 10);
			strategyXml = StrategyUtil.createClientSealStrategyXml("sealStrategy", "china", sealImage, Integer.valueOf(CFCA_SEAL_IMAGE_SIZE), signLocation, Mechanism.SHA1, null);
		}else {//使用系统默认图章
			sealImage = FileUtils.readFileToByteArray(new File(FileUtil.getRootPath(CFCA_SEAL_IMAGE_PATH)));
			signLocation = new SignLocation("签署日期", "R", 40, 10);
			strategyXml = StrategyUtil.createClientSealStrategyXml("sealStrategy", "china", sealImage, Integer.valueOf(60), signLocation, Mechanism.SHA1, null);
		}
		
		
		
		// 获取时间戳的方式。默认值为0。0：实时访问CFCA 时间戳服务；1：使用从CFCA购置并在本地部署的时间戳服务器产品；
		String timestampChannel = "0";
		// 计算hash x509Cert参数可以为空，为空时外部合成签名只能是pkcs7
		String returnMessage = clientBean.autoCalculatePdfHash(bizCode, pdf, null, strategyXml, CFCA_OPERATOR_CODE, CFCA_CHANNEL_CODE, timestampChannel);
		
		if(StringUtils.isNotBlank(returnMessage)) {
			String code = StringUtil.getNodeText(returnMessage, "Code");
			if ("200".equals(code)) {
				String pdfSealHash = StringUtil.getNodeText(returnMessage, "PdfSealHash");// pdf签名hash的base64值
				String id = StringUtil.getNodeText(returnMessage, "Id");// 标识,用来对应后台的缓存数据
				returnObj = new String[] {pdfSealHash, id};
				
				logger.info("pdfSealHash="+pdfSealHash);
				logger.info("id="+id);
			}else {
				logger.info(returnMessage);
				throw new Exception("系统异常，请拔打客服电话400-009-0001或通过在线客服问询处理。");
			}
		}
		return returnObj;
	}

	


	public boolean synthesizeOuterSignature(String signature, String id, String outputPath) {
		
		boolean flag = false;
		
		Example example = new Example(ParamPO.class);
		example.createCriteria().andLike("paraCode", "CFCA_%");
		List<ParamPO> mDDParaList = paramMapper.selectByExample(example);
		
		Map<String, String> paraMap = new HashMap<String, String>();
		if(mDDParaList != null && mDDParaList.size() > 0) {
			for(ParamPO mDDPara:mDDParaList) {
				paraMap.put(mDDPara.getParaCode(), mDDPara.getParaValue());
			}
		}
		
		String CFCA_SERVICE_URL = paraMap.get("CFCA_SERVICE_URL");//cfca服务地址
		String CFCA_CONNECT_TIMEOUT = paraMap.get("CFCA_CONNECT_TIMEOUT");//连接超时时间
		String CFCA_READ_TIMEOUT = paraMap.get("CFCA_READ_TIMEOUT");//读取超时时间
		String CFCA_OPERATOR_CODE = paraMap.get("CFCA_OPERATOR_CODE");//操作员编号
		String CFCA_CHANNEL_CODE = paraMap.get("CFCA_CHANNEL_CODE");//渠道编号
		
		
		logger.info("CFCA_SERVICE_URL="+CFCA_SERVICE_URL);
		logger.info("CFCA_CONNECT_TIMEOUT="+CFCA_CONNECT_TIMEOUT);
		logger.info("CFCA_READ_TIMEOUT="+CFCA_READ_TIMEOUT);
		logger.info("CFCA_OPERATOR_CODE="+CFCA_OPERATOR_CODE);
		logger.info("CFCA_CHANNEL_CODE="+CFCA_CHANNEL_CODE);
		
		logger.info("signature="+signature);
		logger.info("outputPath="+outputPath);
		
		
		
		try {
			// 初始化客户端对象
			PaperlessClient clientBean = new PaperlessClient(CFCA_SERVICE_URL, Integer.valueOf(CFCA_CONNECT_TIMEOUT), Integer.valueOf(CFCA_READ_TIMEOUT));
			// 合成签名
			byte[] sealedPdfData = clientBean.synthesizeOuterSignature(Base64.decode(signature), id, CFCA_OPERATOR_CODE, CFCA_CHANNEL_CODE);
			// 返回错误信息
			String errorRsString = PaperlessClientUtil.isError(sealedPdfData);
			if (StringUtils.isBlank(errorRsString)) {
				IoUtil.write(FileUtil.getRootPath(outputPath), sealedPdfData);
				checkPdfData(sealedPdfData, true);
				flag = true;
			} else {
				// 处理结果为异常，打印出错误码和错误信息
				throw new Exception("签章合成失败:"+errorRsString);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		logger.info("返回标记="+flag);
		return flag;
	}
	
	/**
     * 检查PDF文件是否能验签通过
     * 
     * @param pdfData
     * @param isVerify
     * @throws Exception
     */
    private void checkPdfData(byte[] pdfData, boolean isVerify) throws Exception {
        ValidityUtil.checkPdf(pdfData);
        if (isVerify) {
            PdfSealVerifier pdfSealVerifier = new PdfSealVerifier(pdfData);
            if (!pdfSealVerifier.isPKCS7Valid()) {
            	logger.info("检查PDF文件是否能验签通过:验签失败");
                throw new Exception("验签失败");
            } else {
                PdfArray uncoverdRange = pdfSealVerifier.getUncoveredByteRange();
                long uncoverdRangeLen = uncoverdRange.asLongArray()[1];
                if (uncoverdRangeLen > 0) {
                	logger.info("检查PDF文件是否能验签通过:单据在盖章之后被修改");
                    throw new Exception("单据在盖章之后被修改 ");
                }
            }
        }
    }

}
